#pragma once
#include <lcir/ADT/IList.h>
#include <lcir/ADT/ListNode.h>
#include <lcir/ADT/Range.h>
#include <lcir/IR/Prototype.h>
#include <lcir/IR/Type.h>
#include <lcir/IR/ValuePrinter.h>

#include <memory>
#include <stdexcept>
#include <variant>
namespace lcir {
/// d-u链放在这个里面
/// 纯虚类
class Expression;
class Operand;
class Value {
  using useList = IListRef<Operand>;
  useList users;

 protected:
  std::unique_ptr<Prototype> proto;

 public:
  enum ValueKind { VK_Lambda, VK_VReg, VK_Constant, VK_Argument };

 private:
  ValueKind valueKind;

 public:
  Value(ValueKind vk) : valueKind(vk) {}
  ValueKind getKind() const { return valueKind; }
  // Value将获得Prototype的所有权！
  Prototype *getProto() const { return proto.get(); }
  template <class ProtoTy>
  ProtoTy *getProto() const {
    if (!proto) return nullptr;
    return proto->dyn_cast<ProtoTy>();
  }
  Type *getType() const { return proto->getType(); }

  virtual Expression *getDefExpr() const { return nullptr; }

  // 返回根节点
  Value *getRoot() const;
  // 获得该Value defExpr的parent，若不存在返回nullptr
  Value *getDefExprParent() const;
  useList &getSubList() { return users; }
  useList &getUsers() { return users; };
  /**
   * @brief 如果当前这个value只有一个user,返回该user,否则返回nullptr
   */
  Operand *getSingleUser();
  bool usersEmpty() const { return users.empty(); }
  template <class ProtoTy>
  bool isaProto() const {
    return getProto()->isa<ProtoTy>();
  }
  template <class TypeTy>
  bool isaType() const {
    return getType()->isa<TypeTy>();
  }
  virtual std::string toString(ValuePrinter *) const = 0;

  /// rauw：将operand从Value的useList中删除，在新的Value中插入新的Operand
  void rauw(Value *newValue);
  void addUser(Operand *operand);
  void removeUser(Operand *operand);

  template <class OtherType>
  bool isa() const {
    return getKind() == OtherType::getValueKind();
  }
  template <class OtherType>
  OtherType *dyn_cast() {
    if (!isa<OtherType>()) return nullptr;
    return static_cast<OtherType *>(this);
  }
  template <class OtherType>
  const OtherType *dyn_cast() const {
    if (!isa<OtherType>()) return nullptr;
    return static_cast<const OtherType *>(this);
  }

  template <class OtherType>
  OtherType *cast() {
    if (!isa<OtherType>()) throw std::runtime_error("invalid cast!");
    return static_cast<OtherType *>(this);
  }
  template <class OtherType>
  const OtherType *cast() const {
    if (!isa<OtherType>()) throw std::runtime_error("invalid cast!");
    return static_cast<const OtherType *>(this);
  }

  void setInfo(std::string_view str);
  std::string getInfo() const;
  /**
   * @brief 对当前value尝试进行常量折叠
   */
  Constant *tryFold();
  virtual ~Value() = default;
};

template <class Derived>
class ValueCRTP : public Value {
 public:
  ValueCRTP(ValueKind vk) : Value(vk) {}
  std::string toString(ValuePrinter *printer) const override {
    return printer->print(static_cast<const Derived *>(this));
  }
};

}  // namespace lcir